package ViewPackage;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;

import delta.Field;
import delta.IFieldable;

public class GameView {
	
	public Object viewsync=new Object();
	
	//A bullet hozzaadashoz/torleshez
	public Object bulletsync=new Object();
	
	//A fieldekehez tartozo fedoobjektumok
	private FieldView[][] fieldViews;
	
	//A mezokon talalhato objektumok
	private ArrayList<IFieldableView> IFieldableViews=new ArrayList<IFieldableView>();
		
	//A tenyleges felulet, amire a GameView rajzol
	private GameCanvas gameCanvas ;
	
	//A lovedekek listaja
	LinkedList<Bullet> bullets=new LinkedList<Bullet>();
	//A torlendo lovedekek listaja, mivel a java nem
	LinkedList<Bullet> bulletsToRemove=new LinkedList<Bullet>();
	
	
	//A torlendo objektumok egy kulon listaba kerulnek
	private LinkedList<IFieldableView> toRemove=new LinkedList<IFieldableView>();
	
	MouseView mView=null;
	
	/*
	 * konstruktor
	 * Valtozas a class diagramhoz kepest:
	 * At kell adni az iranyitott jatekkepernyot
	 */
	public GameView(GameCanvas gc,Field[][] fields){
		gameCanvas=gc;
		
		//!itt a kesobbiekben dobni kellene egy hibat ha a fields vagy a gc null
		this.addFields(fields);
		
		
	}
	
	
	/*
	 * Visszater az atadott field alapjan a hozza tartozo FieldView -vel
	 */
	FieldView getFieldView(Field f){
		if(f==null)return null;
		
		for(int i=0;i<fieldViews.length;i++){
			for(int j=0;j<fieldViews[i].length;j++){
				if(fieldViews[i][j].getObservedField()==f)return fieldViews[i][j];
			}
		}
		return null;
	}
	/*
	 * Visszater az atadott koordinatakhoz tartozo fieldView -vel
	 */
	FieldView getFieldView(int x,int y){
		for(int i=0;i<fieldViews.length;i++){
			for(int j=0;j<fieldViews[i].length;j++){
				if(fieldViews[i][j].getXPos()<=x && x<=fieldViews[i][j].getWidth()+fieldViews[i][j].getXPos())
					if(fieldViews[i][j].getYPos()<=y && y<=fieldViews[i][j].getHeight()+fieldViews[i][j].getYPos())return fieldViews[i][j];
			}
		}
		return null;
	}
	
	private void addFields(Field[][] fields){
		Dimension canvasSize=gameCanvas.getPreferredSize();
		
		//A fieldView matrix inicializalasa
		fieldViews=new FieldView[fields.length][fields[0].length];
		
		//A mezok meretenek megallapitasa
		int width=canvasSize.width/fields[0].length;
		int height=canvasSize.height/fields.length;
		
		
		//A matrix mezoihez view -ek letrehozasa es a megfelelo meret beallitasa
		for(int i=0;i<fields.length;i++){
			for(int j=0;j<fields[i].length;j++){
				//utnak szurke szin beallitasa
				fieldViews[i][j]=new FieldView(this,fields[i][j],j*width,i*height,
						fields[i][j].getDistance()==-1?Color.green:Color.getHSBColor((float)(14/240.0), (float)(99/240.0), (float)(128/240.0)));
				//meret beallitasa
				fieldViews[i][j].setWidth(width);
				fieldViews[i][j].setHeight(height);
			}
		}
	}
	
	/*
	 * Hozzaadja a parameterben atadott
	 * IFieldableView -t
	 */
	public void addIFieldableView(IFieldableView obj){
		//szinkronizalni kell mert a ViewControllertol 
		//fuggetlenul hivja meg a listener gomblenyomaskor
		synchronized(viewsync){
			IFieldableViews.add(obj);
			//Hozzaadaskor ujra sorba kell rendezni
			Collections.sort(IFieldableViews);
		}
	}
	
	/*
	 * Megprobalja letorolni a parameterkent atadott objektumot
	 * a keprol
	 */
	public void removeGameObject(IFieldableView obj){
		//itt nem kell szinkronizalni, mert csak hozzadodik egy listahoz,
		//ami a kesobb torlendo objektumokat tartalmazza
			toRemove.add(obj);
			
		
	}
	//Az elozo fuggvenyhez tartozo, a tenyleges torlest vegzo fuggveny
	private void deleteObjects(){
		synchronized(viewsync){
			for(IFieldableView obj:toRemove){
				IFieldableViews.remove(obj);
			}
			//Ekkor rendezett marad
			//A torles utan uj lista keszul
			toRemove=new LinkedList<IFieldableView>();
		}	
	}
	
	/*
	 * A gameView frissitese. Frissiti a GameCanvast.
	 */
	public void update(){
		//A rajzolofelulet lekerdezese
		Graphics g=gameCanvas.getImage();
		Dimension size=gameCanvas.getPreferredSize();
		
		
		//Az elozo kep torlese
		g.setColor(Color.white);
		g.fillRect(0, 0, size.width, size.height);
		
		//======================================================
		//view Update
		//======================================================
		//itt a sorrend is fontos
		
		//A mezok kirajzolasa
		
		for(int i=0;i<fieldViews.length;i++){
			for(int j=0;j<fieldViews[i].length;j++){
				fieldViews[i][j].draw(g);
				
			}
		}
		
		//Az IFieldableViewek kirajzolasa	
		//Amig a listakon vegigmegy, nem szabad hagyni, hogy a modell vagy
		//a jatekos belemodositson a listaba
		synchronized(viewsync){
			for(IFieldableView iview :IFieldableViews){
				iview.draw(g);
			}
		}
		
		synchronized(bulletsync){
			for(Bullet b: bullets){
				b.update(g);
				
			}
		}
		//A mouseView kirajzolasa ha van
		if(mView!=null)mView.draw(g);
		
		//A torlendo objektumok letorlese
		deleteObjects();
		//A torlendo bulletek torlese
		deleteBullets();
		gameCanvas.reDraw();
	}
	
	
	/*
	 * Visszater a GameCanvassal
	 */
	public GameCanvas getCanvas(){
		return gameCanvas;
	}
	
	//MouseView hozzaadasa
	public void addMouseView(MouseView mv){
		mView=mv;
	}
	
	//==========================================================
	//Bullet kezeles
	//==========================================================
	
	//Bullet hozzaadasa
	public void addBullet(FieldView starting, FieldView destination){
		if(starting==null)return;
		if(destination== null)return;
		
		//szinkronizalasa, mert a masik szalrol erkezik a hozzaadasi utasitas
		synchronized(bulletsync){

			
			// itt is ellenorizni kell, mert lehet hogy kozben celbaer az ellenseg
			//Mert az ellensegkezeles egy masik szalon fut
			if(starting==null || destination==null)return;
			//A mezo kozepere helyezes valos osztassal
			double X=Math.round((double)starting.getXPos()+starting.getWidth()/2.0);
			double Y=Math.round((double)starting.getYPos()+starting.getHeight()/2.0);
			
			//A cel koordinatai
			double destX=Math.round((double)destination.getXPos()+destination.getWidth()/2.0);
			double destY=Math.round((double)destination.getYPos()+destination.getHeight()/2.0);
			
			//integerre visszakonvertalas es uj bullet hozzaadasa
			bullets.add(new Bullet((int)X,(int)Y,(int)destX,(int)destY,5, this));
		}
	}
	//A bullet letorlese a kepernyorol
	//ez a fuggveny csak hozzaadja a listahoz
	public void removeBullet(Bullet b){
		bulletsToRemove.add(b);
	}
	
	//Tenylegesen letorli a torlendo Bulleteket
	public void deleteBullets(){
		synchronized(bulletsync){
			for(Bullet b: bulletsToRemove){
				bullets.remove(b);
			}
		}
	}
	
	
	
}
